﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Aphysoft.Vate.Graphics;

using Microsoft.Xna.Framework;

namespace Aphysoft.Vate
{
    public partial class Vate
    {
        #region Properties
        /// <summary>
        /// Gets view matrix from camera used by current projector.
        /// Shortcut of BasePage.ProjectorManager.CurrentProjector.Camera.ViewMatrix.
        /// </summary>
        public static Matrix ViewMatrix
        {
            get
            {
                if (ProjectorManager.Current.Length == 0)
                    return Matrix.Identity;
                else
                    return ProjectorManager.CurrentProjector.Camera.ViewMatrix;
            }
        }
        /// <summary>
        /// Gets projection matrix of current projector.
        /// Shortcut of BasePage.ProjectorManager.CurrentProjector.ProjectionMatrix.
        /// </summary>
        public static Matrix ProjectionMatrix
        {
            get
            {
                if (ProjectorManager.Current.Length == 0)
                    return Matrix.Identity;
                else
                    return ProjectorManager.CurrentProjector.ProjectionMatrix;
            }
        }
        /// <summary>
        /// World Matrix.
        /// </summary>
        private static Matrix worldMatrix = Matrix.Identity;
        /// <summary>
        /// Gets or sets the world matrix.
        /// </summary>
        public static Matrix WorldMatrix
        {
            get { return worldMatrix; }
            set { worldMatrix = value; }
        }
        /// <summary>
        /// Global light direction for shaders.
        /// </summary>
        private static Vector3 lightDirection = new Vector3(0, 0, 1);
        /// <summary>
        /// Global light direction for shaders.
        /// </summary>
        public static Vector3 LightDirection
        {
            get { return lightDirection; }
            set
            {
                lightDirection = value;
                lightDirection.Normalize();
            }
        }

        // performance variables
        private static Matrix _perf_worldMatrix = Matrix.Identity;
        private static Matrix _perf_viewMatrix = Matrix.Identity;
        private static Matrix _perf_projectionMatrix = Matrix.Identity;
        private static Matrix _perf_worldViewProjectionMatrix = Matrix.Identity;
        private static Matrix _perf_viewProjectionMatrix = Matrix.Identity;
        #endregion

        #region Methods
        /// <summary>
        /// Gets the world view projection matrix based on specified camera and projector.
        /// </summary>
        /// <param name="camera">Camera</param>
        /// <param name="projector">Projector</param>
        public static Matrix GetWorldViewProjectionMatrix(Camera camera, Projector projector)
        {
            if (_perf_worldMatrix != worldMatrix ||
                _perf_viewMatrix != camera.ViewMatrix || _perf_projectionMatrix != projector.ProjectionMatrix ||
                _perf_worldViewProjectionMatrix == Matrix.Identity)
            {
                // build
                Matrix viewMatrix = camera.ViewMatrix;
                Matrix projectionMatrix = projector.ProjectionMatrix;

                // update performance variables
                _perf_worldMatrix = worldMatrix;
                _perf_viewMatrix = viewMatrix;
                _perf_projectionMatrix = projectionMatrix;

                _perf_worldViewProjectionMatrix = worldMatrix * viewMatrix * projectionMatrix;
            }

            return _perf_worldViewProjectionMatrix;
        }
        /// <summary>
        /// Gets the world view projection matrix based on current camera and projector.
        /// </summary>
        public static Matrix GetWorldViewProjectionMatrix()
        {
            return GetWorldViewProjectionMatrix(CurrentCamera, CurrentProjector);
        }
        /// <summary>
        /// Gets the view projection matrix based on specified camera and projector.
        /// </summary>
        /// <param name="camera">Camera</param>
        /// <param name="projector">Projector</param>
        public static Matrix GetViewProjectionMatrix(Camera camera, Projector projector)
        {
            if (_perf_viewMatrix != camera.ViewMatrix || _perf_projectionMatrix != projector.ProjectionMatrix ||
                _perf_viewProjectionMatrix == Matrix.Identity)
            {
                // build
                Matrix viewMatrix = camera.ViewMatrix;
                Matrix projectionMatrix = projector.ProjectionMatrix;

                // update performance variables
                _perf_viewMatrix = viewMatrix;
                _perf_projectionMatrix = projectionMatrix;

                _perf_viewProjectionMatrix = viewMatrix * projectionMatrix;
            }

            return _perf_viewProjectionMatrix;
        }
        /// <summary>
        /// Gets the view projection matrix based on current camera and projector.
        /// </summary>
        public static Matrix GetViewProjectionMatrix()
        {
            return GetViewProjectionMatrix(CurrentCamera, CurrentProjector);
        }
        /// <summary>
        /// Gets the inverse view matrix based on current camera.
        /// </summary>
        /// <returns></returns>
        public static Matrix GetInverseViewMatrix()
        {
            return CurrentCamera.InverseViewMatrix;
        }
        #endregion
    }
}
